import codecs
import ctypes

import numpy as np

so = ctypes.cdll.LoadLibrary
lib = so("/home/yjy/VSCodeProjects/palmMatch/build/libfeatureExtractor.so")
lib.calculate_codes_distance.restype = ctypes.c_double
c_hamming_dist_kernel = lib.calculate_codes_distance


def cosin_metric(x1, x2):
    result = np.dot(x1, x2) / (np.linalg.norm(x1) * np.linalg.norm(x2))
    result = 1 if result > 1 else result
    return result


def angular_metric(x1, x2):
    return - angular_dist(x1, x2)


def cos_dist(probeFv, refFv):
    dist = - cosin_metric(probeFv, refFv)
    return dist


def angular_dist(probeFv, refFv):
    angles = np.arccos(cosin_metric(probeFv, refFv))
    return angles


def byte2int(b):
    if b == '':
        i = 0
    else:
        i = int(codecs.encode(b, 'hex'), 16)
    return i


def c_hamming_dist(probeFv, refFv):
    # A = ctypes.create_string_buffer(512).from_buffer(source=probeFv.tobytes())
    # B = ctypes.create_string_buffer(512).from_buffer(source=refFv.tobytes())
    # A = np.array(map(byte2int, probeFv))
    # B = np.array(map(byte2int, refFv))
    # dist = euclid_dist(A, B)
    A = probeFv.tobytes()
    B = refFv.tobytes()
    dist = c_hamming_dist_kernel(A, B)
    return dist


def euclid_dist(x, y):
    return np.linalg.norm(x - y)


def one_norm_dist(x, y):
    return np.linalg.norm(x - y, ord=1)


def hamming_dist(x, y):
    x = x.astype(np.int32)
    y = y.astype(np.int32)
    result = np.bitwise_xor(x, y)
    miss = np.where(result != 0)
    dist = float(len(miss[0])) / len(result)
    return dist
